//
// Created by DELL on 2023/4/27.
//

#include <iostream>

class Base
{
public:
    Base()
    {
        std::cout << "Base Construct.  ";
        this->fun2("Base::Base");
    }

    virtual ~Base()
    {
        std::cout << "Base Destruct.  ";
        this->fun2("Base::~Base");
    }

    virtual void fun()
    {
        std::cout << "Base::fun" << std::endl;
    }

    virtual void fun2(const char* caller)
    {
        std::cout << "Base::fun2, caller: " << caller << std::endl;
    }
    int m{10};
};

class Base2
{
public:
    int n{0};
};

class Derive : public Base, public Base2
{
public:
    Derive()
    {
        std::cout << "Derive Construct.  ";
        Derive::fun2("Derive::Derive");
    }

    ~Derive() override
    {
        std::cout << "Derive Destruct.  ";
        Derive::fun2("Derive::~Derive");
    }

    void fun2(const char* caller) override
    {
        std::cout << "Derive::fun2: caller: " << caller << std::endl;
    }

    void fun() override
    {
        std::cout << "Derive::fun" << std::endl;
    }
};

class Base3
{
public:
    Base3()
    {
        std::cout << "Base3 Construct.  " << std::endl;
    }

    virtual ~Base3()
    {
        std::cout << "Base3 Destruct.  " << std::endl;
    }

    virtual void fun()
    {
        std::cout << "Base3::fun  " << std::endl;
    }
};

class Derive3 : public  Base, public Base3
{
public:
    Derive3()
    {
        std::cout << "Derive3 Construct.  " << std::endl;
    }

    ~Derive3() override
    {
        std::cout << "Derive3 Destruct.  " << std::endl;
    }

    virtual void deriveFun()
    {
        std::cout << "Derive3::deriveFun  " << std::endl;
    }
};

int main()
{
    {
        std::cout << "-------------------Type Cast------------------------" << std::endl;

        Base *d1 = new Derive;
        auto b21 = (Base2*)d1; // 得到错误的结果
        //    auto b22 = static_cast<Base2*>(p); // compile error!!
        auto b23 = dynamic_cast<Base2*>(d1);
        std::cout << "b21 Base2::n: " << b21->n << std::endl;
        std::cout << "b23 Base2::n: " << b23->n << std::endl;
        if (b21 == b23)
        {
            std::cout << "b21 == b23" << std::endl;
        }
        else
        {
            // 两者不相等
            std::cout << "b21 != b23" << std::endl;
        }

        delete d1;
        std::cout << std::endl;
    }

    {
        std::cout << "-------------------Static Cast------------------------" << std::endl;
        Base2* b2 = new Base2;
        auto d2 = static_cast<Derive*>(b2); // 错误的转换，会对地址做固定定的偏移
        std::cout << "d2 Base::m: " << d2->m << std::endl;
        std::cout << "b2:" << b2 << ", d2: " << d2 << std::endl;
        delete b2;
        std::cout << std::endl;
    }

    {
        std::cout << "-------------------Virtual Function Call------------------------" << std::endl;

        Base *p = new Derive;

       std::cout << "p->fun2(\"main\")： "; p->fun2("main");

       std::cout << "p->fun(): "; p->fun();

       std::cout << "(*p).fun(): "; (*p).fun();

       std::cout << "p->Base::fun(): "; p->Base::fun();

       // 获取的是虚函数的索引，不是实际的函数地址，所以依然有多态的效果
        auto pBFun = &Base::fun;
        auto pDFun = &Derive::fun;

        std::cout << "(p->*pBFun)(): "; (p->*pBFun)();
        std::cout << "((Derive*)p->*pDFun)(): "; ((Derive*)p->*pDFun)();
        delete p;

        std::cout << std::endl;
    }

    {
        // Virtual Table https://zhuanlan.zhihu.com/p/611317234
        std::cout << "-------------------Virtual Class Size------------------------" << std::endl;

        Derive3 derive3;
        std::cout<< "sizeof(Base): " << sizeof(Base) << std::endl;
        std::cout<< "sizeof(Base3): " << sizeof(Base3) << std::endl;
        std::cout<< "sizeof(Derive3): " << sizeof(Derive3) << std::endl;

        std::cout<< "Derive3 Address: 0x"<< (void*)&derive3 << std::endl;
        std::cout<< "Base Address: 0x"<< (void*)(Base*)&derive3 << std::endl;
        std::cout<< "Base3 Address: 0x"<< (void*)(Base3*)&derive3 << std::endl;
        std::cout<< "Base3 diff Base: " << reinterpret_cast<intptr_t>((Base3*)&derive3) - reinterpret_cast<intptr_t>((Base*)&derive3) << std::endl;

        std::cout << std::endl;
        derive3.deriveFun();
    }

    return 0;
}